/*
** $Id: ltable.c $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/

#define ltable_c
#define LUA_CORE

#include "lprefix.h"


/*
** 表(也是包含数组，对象，hash表)
** table在两个部分保存元素：数组部分和hash部分
** 非负整数key都是保存在数组部分的候选key
** 数组的实际大小是最大的n(最大的非负整数key)，至少一半的节点在1-n之间
** 哈希使用了Brent变量的链式hash表的混合
** 这些表的一个主要不变量是，如果一个元素不在它的主位置(即哈希给它的“原始”位置)，那么冲突元素就在它自己的主位置
** 因此，即使负载系数达到100%，性能仍然很好
*/

#include <math.h>
#include <limits.h>

#include "lua.h"

#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"


/*
** MAXABITS: 使 MAXASIZE 能放入一个无符号整数的最大位数
*/
#define MAXABITS	cast_int(sizeof(int) * CHAR_BIT - 1)


/*
** MAXASIZE 数组部分的最大长度
** 在 2^MAXABITS 和 最大 size 之间，确保以字节为单位时在'size_t'范围内
*/
#define MAXASIZE	luaM_limitN(1u << MAXABITS, TValue)

/*
** MAXHBITS: 使 2^MAXHBITS 能放在一个有符号整数的最大整数
*/
#define MAXHBITS	(MAXABITS - 1)


/*
** MAXHSIZE hash部分的最大长度
** 在 2^MAXHBITS 和 最大 size 之间，确保以字节为单位时在'size_t'范围内
*/
#define MAXHSIZE	luaM_limitN(1u << MAXHBITS, Node)


/*
** 当原始hash值是好的时，使用 2 的次方来避免 '%'的消耗
*/
#define hashpow2(t,n)		(gnode(t, lmod((n), sizenode(t))))

/*
** 对于其他类型，最好避免以2的幂取模，因为它们可以有许多2的因子
*/
#define hashmod(t,n)	(gnode(t, ((n) % ((sizenode(t)-1)|1))))


#define hashstr(t,str)		hashpow2(t, (str)->hash)
#define hashboolean(t,p)	hashpow2(t, p)


#define hashpointer(t,p)	hashmod(t, point2uint(p))


#define dummynode		(&dummynode_)

// 虚拟节点
static const Node dummynode_ = {
  {{NULL}, LUA_VEMPTY,  /* 值的值和类型 */
   LUA_VNIL, 0, {NULL}}  /* 键类型，下一个，键的值 */
};

// 缺省key
static const TValue absentkey = {ABSTKEYCONSTANT};


/*
** 整数的hash，为了允许一个优秀的hash，使用取模操作符('%')，如果整数是一个非负整数，计算整数的模，否则，使用一个无符号整数模，他使用所有位来保证非负结果
*/
static Node *hashint (const Table *t, lua_Integer i) {
  lua_Unsigned ui = l_castS2U(i);
  if (ui <= cast_uint(INT_MAX)) // 非负整数
    return hashmod(t, cast_int(ui));
  else
    return hashmod(t, ui);
}


/*
** 浮点数的hash值
** The main computation should be just
**     n = frexp(n, &i); return (n * INT_MAX) + i
** but there are some numerical subtleties.
** In a two-complement representation, INT_MAX does not has an exact
** representation as a float, but INT_MIN does; because the absolute
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
** INT_MIN.
*/
#if !defined(l_hashfloat)
static int l_hashfloat (lua_Number n) {
  int i;
  lua_Integer ni;
  n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
  if (!lua_numbertointeger(n, &ni)) {  /* is 'n' inf/-inf/NaN? */
    lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
    return 0;
  }
  else {  /* normal case */
    unsigned int u = cast_uint(i) + cast_uint(ni);
    return cast_int(u <= cast_uint(INT_MAX) ? u : ~u);
  }
}
#endif


/*
** 返回一个元素在table中的main position(hash值对应的索引)
*/
static Node *mainpositionTV (const Table *t, const TValue *key) {
  switch (ttypetag(key)) {
    case LUA_VNUMINT: {
      lua_Integer i = ivalue(key);
      return hashint(t, i);
    }
    case LUA_VNUMFLT: {
      lua_Number n = fltvalue(key);
      return hashmod(t, l_hashfloat(n));
    }
    case LUA_VSHRSTR: {
      TString *ts = tsvalue(key);
      return hashstr(t, ts);
    }
    case LUA_VLNGSTR: {
      TString *ts = tsvalue(key);
      return hashpow2(t, luaS_hashlongstr(ts));
    }
    case LUA_VFALSE:
      return hashboolean(t, 0);
    case LUA_VTRUE:
      return hashboolean(t, 1);
    case LUA_VLIGHTUSERDATA: {
      void *p = pvalue(key);
      return hashpointer(t, p);
    }
    case LUA_VLCF: {
      lua_CFunction f = fvalue(key);
      return hashpointer(t, f);
    }
    default: {
      GCObject *o = gcvalue(key);
      return hashpointer(t, o);
    }
  }
}

// 通过node获取main position
l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
  TValue key;
  getnodekey(cast(lua_State *, NULL), &key, nd);
  return mainpositionTV(t, &key);
}


/*
** 检测key 'k1'是否和node 'n2'的节点key相同，这个等式是原生的，不会使用元方法，不会进行类型转换(如float和integer的转换)
** deadok: 是否接收已经移除的key，在默认情况下，通过指针标识比较所有deadkey。(只有可收集的物品才能产生deadkey)
*/
static int equalkey (const TValue *k1, const Node *n2, int deadok) {
  if ((rawtt(k1) != keytt(n2)) &&  /* 类型变体不同? */
       !(deadok && keyisdead(n2) && iscollectable(k1)))
   return 0;
  switch (keytt(n2)) {
    case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
      return 1;
    case LUA_VNUMINT:
      return (ivalue(k1) == keyival(n2));
    case LUA_VNUMFLT:
      return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
    case LUA_VLIGHTUSERDATA:
      return pvalue(k1) == pvalueraw(keyval(n2));
    case LUA_VLCF:
      return fvalue(k1) == fvalueraw(keyval(n2));
    case ctb(LUA_VLNGSTR):
      return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
    default:
      return gcvalue(k1) == gcvalueraw(keyval(n2));
  }
}


/*
** 如果‘alimit'等于数组表数组部分的真实大小则返回true (否则，数组部分必须大于’alimit')
*/
#define limitequalsasize(t)	(isrealasize(t) || ispow2((t)->alimit))


/*
** 数组部分的真实大小
*/
LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
  if (limitequalsasize(t))
    return t->alimit;
  else {
    unsigned int size = t->alimit;
    /* 计算2不小于n的最小次幂 */
    size |= (size >> 1);
    size |= (size >> 2);
    size |= (size >> 4);
    size |= (size >> 8);
#if (UINT_MAX >> 14) > 3  /* 无符号整数超过16个位 */
    size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
    size |= (size >> 32);  /* 无符号整数超过32个位 */
#endif
#endif
    size++;
    lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
    return size;
  }
}


/*
** 检查数组部分真实大小是否是2的次幂，如果不是，在不改变实际大小的情况下，'alimit'不能更改为任何其他值。
*/
static int ispow2realasize (const Table *t) {
  return (!isrealasize(t) || ispow2(t->alimit));
}

// 将alimit设置为数组部分真实长度
static unsigned int setlimittosize (Table *t) {
  t->alimit = luaH_realasize(t);
  setrealasize(t);
  return t->alimit;
}


#define limitasasize(t)	check_exp(isrealasize(t), t->alimit)


/*
** 通用的get版本(不通用的情况：数组部分的整数、具有整数值的浮点数)
*/
static const TValue *getgeneric (Table *t, const TValue *key, int deadok) {
  Node *n = mainpositionTV(t, key);
  for (;;) {  /* 检查“key”是否在链中的某个位置 */
    if (equalkey(key, n, deadok))
      return gval(n);  /* that's it */
    else {
      int nx = gnext(n);
      if (nx == 0)
        return &absentkey;  /* not found */
      n += nx;
    }
  }
}


/*
** 如果k是一个合适的数组部分key则返回k的索引，否则返回0
*/
static unsigned int arrayindex (lua_Integer k) {
  if (l_castS2U(k) - 1u < MAXASIZE)  /* 'k' in [1, MAXASIZE]? */
    return cast_uint(k);  /* 'key'相应的数组索引 */
  else
    return 0;
}


/*
** 返回表遍历的key索引，首先是数组部分的所有元素，然后是hash部分，遍历的开始使用0表示
*/
static unsigned int findindex (lua_State *L, Table *t, TValue *key,
                               unsigned int asize) {
  unsigned int i;
  if (ttisnil(key)) return 0;  /* 第一次迭代 */
  i = ttisinteger(key) ? arrayindex(ivalue(key)) : 0;
  if (i - 1u < asize)  /* 'key'在数组部分? */
    return i;  /* yes; that's the index */
  else {
    const TValue *n = getgeneric(t, key, 1);
    if (l_unlikely(isabstkey(n)))
      luaG_runerror(L, "invalid key to 'next'");  /* key not found */
    i = cast_int(nodefromval(n) - gnode(t, 0));  /* hash部分的key索引 */
    /* hash部分计数为array部分之后的 */
    return (i + 1) + asize;
  }
}

// lua的next函数(找到下一个非空元素(key之后的))
int luaH_next (lua_State *L, Table *t, StkId key) {
  unsigned int asize = luaH_realasize(t);
  unsigned int i = findindex(L, t, s2v(key), asize);  /* find original key */
  for (; i < asize; i++) {  // 查找数组后面的部分不为空的
    if (!isempty(&t->array[i])) {  /* a non-empty entry? */
      setivalue(s2v(key), i + 1);
      setobj2s(L, key + 1, &t->array[i]);
      return 1;
    }
  }
  for (i -= asize; cast_int(i) < sizenode(t); i++) {
    if (!isempty(gval(gnode(t, i)))) {  /* a non-empty entry? */
      Node *n = gnode(t, i);
      getnodekey(L, s2v(key), n);
      setobj2s(L, key + 1, gval(n));
      return 1;
    }
  }
  return 0;  /* no more elements */
}

// 释放hash部分
static void freehash (lua_State *L, Table *t) {
  if (!isdummy(t))
    luaM_freearray(L, t->node, cast_sizet(sizenode(t)));
}


/*
** {=============================================================
** Rehash
** ==============================================================
*/

/*
** 计算表的最优数组部分大小
** nums: 计数数组，num[i]表示出现在2^(i-1)和2^i之间的key的个数
** pna: 传入时表的整数key的总个数，离开函数时为数组部分key的总个数
** ('twotoi > 0'用于在twotoi溢出时停止循环)
*/
static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
  int i;
  unsigned int twotoi;  /* 2^i (最优大小候选) */
  unsigned int a = 0;  /* 小于2^i的元素个数 */
  unsigned int na = 0;  /* 需要放入数组部分的元素个数 */
  unsigned int optimal = 0;  /* 数组部分的最优大小 */
  /* key可以填满总大小的一半以上时循环 */
  for (i = 0, twotoi = 1;
       twotoi > 0 && *pna > twotoi / 2;
       i++, twotoi *= 2) {
    a += nums[i];
    if (a > twotoi/2) {  /* 出现了超过一半的元素？ */
      optimal = twotoi;  /* 目前的最优大小 */
      na = a;  /* 所有达到“optimal”的元素都将放入数组部分 */
    }
  }
  lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
  *pna = na;
  return optimal;
}


// 计算整数key出现的个数，用于computesizes的nums
static int countint (lua_Integer key, unsigned int *nums) {
  unsigned int k = arrayindex(key);
  if (k != 0) {  /* 'key'是一个合适的数组部分索引? */
    nums[luaO_ceillog2(k)]++;  /* 计数 */
    return 1;
  }
  else
    return 0;
}


/*
** 对’t'的数组部分key进行计数：'nums[i]'为相应切片的key数量，并返回非nil键的总数量。
*/
static unsigned int numusearray (const Table *t, unsigned int *nums) {
  int lg;
  unsigned int ttlg;  /* 2^lg */
  unsigned int ause = 0;  /* 'nums'的总数 */
  unsigned int i = 1;  /* 遍历的所有数组key计数 */
  unsigned int asize = limitasasize(t);  /* 真实数组大小 */
  for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) {
    unsigned int lc = 0;  /* 计数 */
    unsigned int lim = ttlg;
    if (lim > asize) {
      lim = asize;  /* 适配上限 */
      if (i > lim)
        break;  /* 没有更多的元素需要计数了 */
    }
    /* 统计key在 2^(lg-1) 至 2^lg 之间的元素个数 */
    for (; i <= lim; i++) {
      if (!isempty(&t->array[i-1]))
        lc++;
    }
    nums[lg] += lc;
    ause += lc;
  }
  return ause;
}


// 对‘t'的hash部分key进行计数
static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
  int totaluse = 0;  /* 元素总数 */
  int ause = 0;  /* 添加到’nums‘中的元素个数(能够放入数组部分的key) */
  int i = sizenode(t);
  while (i--) {
    Node *n = &t->node[i];
    if (!isempty(gval(n))) {
      if (keyisinteger(n))
        ause += countint(keyival(n), nums);
      totaluse++;
    }
  }
  *pna += ause;
  return totaluse;
}


/*
** 通过size为表的hash部分创建一个数组，或者在size为0时重用虚拟节点
** size溢出计算氛围两步：第一次的比较确保第二次比较中的移位不会溢出
*/
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
  if (size == 0) {  /* hash部分没有节点? */
    t->node = cast(Node *, dummynode);  /* 使用公共虚拟节点 */
    t->lsizenode = 0;
    t->lastfree = NULL;  /* 使用虚拟节点标记 */
  }
  else {
    int i;
    int lsize = luaO_ceillog2(size);
    if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
      luaG_runerror(L, "table overflow");
    size = twoto(lsize);
    t->node = luaM_newvector(L, size, Node);
    for (i = 0; i < cast_int(size); i++) {
      Node *n = gnode(t, i);
      gnext(n) = 0;
      setnilkey(n);
      setempty(gval(n));
    }
    t->lsizenode = cast_byte(lsize);
    t->lastfree = gnode(t, size);  /* 所有节点都是空闲的 */
  }
}

/*
** 将‘ot'的hash部分的所有元素重新插入到’t'中
*/
static void reinsert (lua_State *L, Table *ot, Table *t) {
  int j;
  int size = sizenode(ot);
  for (j = 0; j < size; j++) {
    Node *old = gnode(ot, j);
    if (!isempty(gval(old))) {
      /* 不需要屏障/失效缓存，因为条目已经存在于表中 */
      TValue k;
      getnodekey(L, &k, old);
      luaH_set(L, t, &k, gval(old));
    }
  }
}


/*
** 交换’t1’和‘t2’的hash部分
*/
static void exchangehashpart (Table *t1, Table *t2) {
  lu_byte lsizenode = t1->lsizenode;
  Node *node = t1->node;
  Node *lastfree = t1->lastfree;
  t1->lsizenode = t2->lsizenode;
  t1->node = t2->node;
  t1->lastfree = t2->lastfree;
  t2->lsizenode = lsizenode;
  t2->node = node;
  t2->lastfree = lastfree;
}


/*
** 调整表't'的大小为newasize
** newasize: 新的数组部分大小
** newhsize: 新的hash部分大小
** (对于哈希部分和数组部分)都可能会失败，这会产生一些微妙之处。
** 如果哈希部分的第一次分配失败，则会引发错误
** 否则，它将从数组的收缩部分(如果正在收缩)复制元素到新的散列中。然后重新分配数组部分。
** 如果失败，表将处于原始状态;该函数释放新的散列部分，然后引发分配错误。否则，它将把新的哈希部分设置到表中，用nil初始化数组的新部分(如果有的话)，并将旧哈希的元素重新插入到表的新部分中。
*/
void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
                                          unsigned int nhsize) {
  unsigned int i;
  Table newt;  /* 保留新的hash部分 */
  unsigned int oldasize = setlimittosize(t);
  TValue *newarray;
  /* 通过相应的大小创建‘newt'的hash部分 */
  setnodevector(L, &newt, nhsize);
  if (newasize < oldasize) {  /* 数组部分缩小了？ */
    t->alimit = newasize;  /* 假设数组新大小... */
    exchangehashpart(t, &newt);  /* 将hash部分设置到‘newt’中 */
    /* 将数组部分中oldsize-newsize中的元素放入hash部分 */
    for (i = newasize; i < oldasize; i++) {
      if (!isempty(&t->array[i]))
        luaH_setint(L, t, i + 1, &t->array[i]);
    }
    t->alimit = oldasize;  /* 恢复当前大小... */
    exchangehashpart(t, &newt);  /* 和hash部分 (发生错误时) */
  }
  /* 分配新数组 */
  newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
  if (l_unlikely(newarray == NULL && newasize > 0)) {  /* 分配失败？ */
    freehash(L, &newt);  /* 释放新的hash部分 */
    luaM_error(L);  /*  引发错误 (数组没有修改) */
  }
  /* 分配成功初始化新的数组部分 */
  exchangehashpart(t, &newt);  /* 't' 拥有新的hash ('newt' 有老的hash) */
  t->array = newarray;  /* 设置新的数组部分 */
  t->alimit = newasize;
  for (i = oldasize; i < newasize; i++)  /* 清空数组的新的部分 */
     setempty(&t->array[i]);
  /* 将老的hash部分重新插入到新的hash部分 */
  reinsert(L, &newt, t);  /* 'newt'现在有老的hash */
  freehash(L, &newt);  /* 释放老hash部分内存 */
}

// 为数组部分重新分配大小
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
  int nsize = allocsizenode(t);
  luaH_resize(L, t, nasize, nsize);
}

/*
** nums[i] =  2^(i - 1) 和 2^i 之间的key的个数
*/
static void rehash (lua_State *L, Table *t, const TValue *ek) {
  unsigned int asize;  /* 数组的最佳大小 */
  unsigned int na;  /* 数组部分的key个数 */
  unsigned int nums[MAXABITS + 1];
  int i;
  int totaluse;
  for (i = 0; i <= MAXABITS; i++) nums[i] = 0;  /* 初始化nums */
  setlimittosize(t);
  na = numusearray(t, nums);  /* 数组部分keys计数 */
  totaluse = na;  /* 所有的这些key都是整数key */
  totaluse += numusehash(t, nums, &na);  /* hash部分的key计数 */
  /* 统计额外的key(触发rehash操作的key) */
  if (ttisinteger(ek))
    na += countint(ivalue(ek), nums);
  totaluse++;
  /* 重新计算数组部分的新大小 */
  asize = computesizes(nums, &na);
  /* 重新设置table的大小为新计算出来的大小 */
  luaH_resize(L, t, asize, totaluse - na);
}



/*
** }=============================================================
*/


Table *luaH_new (lua_State *L) {
  GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
  Table *t = gco2t(o);
  t->metatable = NULL;
  t->flags = cast_byte(maskflags);  /* 没有元方法field */
  // 数组部分
  t->array = NULL;
  t->alimit = 0;
  // 设置hash部分
  setnodevector(L, t, 0);
  return t;
}

// 释放table
void luaH_free (lua_State *L, Table *t) {
  freehash(L, t);
  luaM_freearray(L, t->array, luaH_realasize(t));
  luaM_free(L, t);
}

static Node *getfreepos (Table *t) {
  if (!isdummy(t)) {
    while (t->lastfree > t->node) {
      t->lastfree--;
      if (keyisnil(t->lastfree))
        return t->lastfree;
    }
  }
  return NULL;  /* 找不到空闲位置 */
}



/*
** 添加一个新的key到hash表，首先，检查key的主位置是否空闲，如果没有，检测碰撞节点是否在他的main position：
** 如果没有，移动碰撞节点到空位置并且放一个新的key到他的main position，否则创建一个新key到一个空位置
*/
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
  Node *mp;
  TValue aux;
  if (l_unlikely(ttisnil(key)))
    luaG_runerror(L, "table index is nil");
  else if (ttisfloat(key)) {
    lua_Number f = fltvalue(key);
    lua_Integer k;
    if (luaV_flttointeger(f, &k, F2Ieq)) {  /* 是个整数? */
      setivalue(&aux, k);
      key = &aux;  /* 作为整数插入 */
    }
    else if (l_unlikely(luai_numisnan(f)))
      luaG_runerror(L, "table index is NaN");
  }
  if (ttisnil(value))
    return;  /* 不插入nil值 */
  mp = mainpositionTV(t, key);
  if (!isempty(gval(mp)) || isdummy(t)) {  /* main position已经被霸占? */
    Node *othern;
    Node *f = getfreepos(t);  /* 获取一个空闲位置 */
    if (f == NULL) {  /* 不能找到空闲位置或者isdummy(t)是true? */
      rehash(L, t, key);  /* 扩展table */
      luaH_set(L, t, key, value);  /* 添加进新的table中 */
      return;
    }
    lua_assert(!isdummy(t));
    othern = mainpositionfromnode(t, mp);
    if (othern != mp) {  /* 碰撞节点不在他自己的main position? */
      /* 将碰撞节点移动到空闲位置 */
      while (othern + gnext(othern) != mp)  /* 查找前一个位置 */
        othern += gnext(othern);
      gnext(othern) = cast_int(f - othern);  /* 重新连接点至'f' */
      *f = *mp;  /* 复制碰撞节点至空闲节点 (mp->next也跟着走) */
      if (gnext(mp) != 0) {
        gnext(f) += cast_int(mp - f);  /* correct 'next' */
        gnext(mp) = 0;  /* now 'mp' is free */
      }
      setempty(gval(mp));
    }
    else {  /* 碰撞节点在他自己的main position */
      /* 新节点将进入空闲节点 */
      if (gnext(mp) != 0)
        gnext(f) = cast_int((mp + gnext(mp)) - f);  /* 链接新位置 */
      else lua_assert(gnext(f) == 0);
      gnext(mp) = cast_int(f - mp);
      mp = f;
    }
  }
  setnodekey(L, mp, key);
  luaC_barrierback(L, obj2gco(t), key);
  lua_assert(isempty(gval(mp)));
  setobj2t(L, gval(mp), value);
}


/*
** 整数搜索函数，如果整数在‘alimit’之内，直接从数组部分获取他
** 否则，如果‘alimit'不等于数组的真实长度， key仍然可能在数组部分，这种情况，当key只比限制多一个时尽量避免使用‘luaH_realasize’(这样就可以在不改变数组的实际大小的情况下增加它)
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
  if (l_castS2U(key) - 1u < t->alimit)  /* 'key' 在 [1, t->alimit]? */
    return &t->array[key - 1];
  else if (!limitequalsasize(t) &&  /* key仍然可能在数组中? */
           (l_castS2U(key) == t->alimit + 1 ||  // 在当前alimit后面一个位置，这个时候key为新的alimit
            l_castS2U(key) - 1u < luaH_realasize(t))) {
    t->alimit = cast_uint(key);  /* 可能'#t'就在这里 */
    return &t->array[key - 1];
  }
  else {
    Node *n = hashint(t, key);
    for (;;) {  /* 检测'key'是否在链中 */
      if (keyisinteger(n) && keyival(n) == key)
        return gval(n);
      else {
        int nx = gnext(n);
        if (nx == 0) break;
        n += nx;
      }
    }
    return &absentkey;
  }
}


/*
** 短字符串搜索函数
*/
const TValue *luaH_getshortstr (Table *t, TString *key) {
  Node *n = hashstr(t, key);
  lua_assert(key->tt == LUA_VSHRSTR);
  for (;;) {  /* 检查‘key'是否在链中某个位置 */
    if (keyisshrstr(n) && eqshrstr(keystrval(n), key))
      return gval(n);  /* that's it */
    else {
      int nx = gnext(n);
      if (nx == 0)
        return &absentkey;  /* 没有找到，返回缺省值 */
      n += nx;
    }
  }
}


const TValue *luaH_getstr (Table *t, TString *key) {
  if (key->tt == LUA_VSHRSTR)
    return luaH_getshortstr(t, key);
  else {  /* 对于长字符串，使用通用逻辑 */
    TValue ko;
    setsvalue(cast(lua_State *, NULL), &ko, key);
    return getgeneric(t, &ko, 0);
  }
}


/*
** 主要的查询函数
*/
const TValue *luaH_get (Table *t, const TValue *key) {
  switch (ttypetag(key)) {
    case LUA_VSHRSTR: return luaH_getshortstr(t, tsvalue(key));
    case LUA_VNUMINT: return luaH_getint(t, ivalue(key));
    case LUA_VNIL: return &absentkey;
    case LUA_VNUMFLT: {
      lua_Integer k;
      if (luaV_flttointeger(fltvalue(key), &k, F2Ieq)) /* 整数索引? */
        return luaH_getint(t, k);  /* 使用特殊版本 */
      /* else... */
    }  /* 下沉 */
    default:
      return getgeneric(t, key, 0);
  }
}


/*
** 完成一次原生的’set table‘操作，’slot‘表示值应该在的位置(前一次’get table‘的结果).
** 注意: 使用该函数时可能需要检查GC屏障并且使TM缓存失效
*/
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
                                   const TValue *slot, TValue *value) {
  if (isabstkey(slot))
    luaH_newkey(L, t, key, value);
  else
    setobj2t(L, cast(TValue *, slot), value);
}


/*
** 注意: 使用该函数时可能需要检查GC屏障并且使TM缓存失效
*/
void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
  const TValue *slot = luaH_get(t, key);  // 查找key的位置
  luaH_finishset(L, t, key, slot, value);
}


void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
  const TValue *p = luaH_getint(t, key);
  if (isabstkey(p)) {
    TValue k;
    setivalue(&k, key);
    luaH_newkey(L, t, &k, value);
  }
  else
    setobj2t(L, cast(TValue *, p), value);
}


/*
** 尝试在表的hash部分查找，通过调用者，我们知道’j'是0或者存在并且‘j+1'存在
 From the caller, we know that 'j' is zero or present and that 'j + 1' is present. 
** We want to find a larger key that is absent from the table, so that we can do a binary search between the two keys to find a boundary.  We keep doubling 'j' until we get an absent index.
** If the doubling would overflow, we try LUA_MAXINTEGER. If it is
** absent, we are ready for the binary search. ('j', being max integer,
** is larger or equal to 'i', but it cannot be equal because it is
** absent while 'i' is present; so 'j > i'.) Otherwise, 'j' is a
** boundary. ('j + 1' cannot be a present integer key because it is
** not a valid integer in Lua.)
*/
static lua_Unsigned hash_search (Table *t, lua_Unsigned j) {
  lua_Unsigned i;
  if (j == 0) j++;  /* the caller ensures 'j + 1' is present */
  do {
    i = j;  /* 'i' is a present index */
    if (j <= l_castS2U(LUA_MAXINTEGER) / 2)
      j *= 2;
    else {
      j = LUA_MAXINTEGER;
      if (isempty(luaH_getint(t, j)))  /* t[j] not present? */
        break;  /* 'j' now is an absent index */
      else  /* weird case */
        return j;  /* well, max integer is a boundary... */
    }
  } while (!isempty(luaH_getint(t, j)));  /* repeat until an absent t[j] */
  /* i < j  &&  t[i] present  &&  t[j] absent */
  while (j - i > 1u) {  /* do a binary search between them */
    lua_Unsigned m = (i + j) / 2;
    if (isempty(luaH_getint(t, m))) j = m;
    else i = m;
  }
  return i;
}


static unsigned int binsearch (const TValue *array, unsigned int i,
                                                    unsigned int j) {
  while (j - i > 1u) {  /* binary search */
    unsigned int m = (i + j) / 2;
    if (isempty(&array[m - 1])) j = m;
    else i = m;
  }
  return i;
}


/*
** table的#操作符
** 尝试找到表的边界(一个整数索引，使得t[i]存在而t[i+1]不存在，如果t[1]不存在则为0，如果t[maxinteger]存在则为maxinteger)
** (在下面的解释中，我们使用Lua索引(以1开始)。 代码本身使用table中数组部分的基于0的的索引)，代码从'limit = t->alimit'开始(可能是数组部分的边界位置)
**
** (1) 如果't[limit]'为空, 边界一定在这之前
** 一种常见情况(例如，在't[#t]=nil'之后)，检查'limit-1'是否存在，如果存在，他就是边界，
** 否则，做0至limit之间做一次二分搜索以查找边界，
** 在这两种情况下，尝试使用这个边界作为新的’limit'，作为下一次调用的提示。
**
** (2) 如果't[limit]'不为空并且数组有‘limit'之后的元素，尝试在这找到边界
** 首先尝试一个特殊的情况: 'limit+1'是空的，因此’limit'就是边界，
** 否则，检查数组的最后一个元素，如果他是空，那么检查老的‘limit'(如果存在)和最后一个元素之间(通过二分查找到的)必须存在一个边界(这个边界总是会变成一个新的limit)
**
** (3) 当数组部分没有元素(limit == 0)或者他的最后一个元素(新limit)存在，这种情况，必须检查hash部分
** 如果没有hash部分或者’limit + 1‘不存在，’limit'就是边界，否则，调用‘hash_search'在表的hash部分查找边界
** (在这些情况下，边界不在数组部分内，因此不能用作新的limit。)
*/
lua_Unsigned luaH_getn (Table *t) {
  unsigned int limit = t->alimit;

  if (limit > 0 && isempty(&t->array[limit - 1])) {  /* (1)? */
    /* 边界一定在'limit'之前 */
    if (limit >= 2 && !isempty(&t->array[limit - 2])) {
      /* 'limit - 1' is a boundary; can it be a new limit? */
      if (ispow2realasize(t) && !ispow2(limit - 1)) {
        t->alimit = limit - 1;
        setnorealasize(t);  /* now 'alimit' is not the real size */
      }
      return limit - 1;
    }
    else {  /* must search for a boundary in [0, limit] */
      unsigned int boundary = binsearch(t->array, 0, limit);
      /* can this boundary represent the real size of the array? */
      if (ispow2realasize(t) && boundary > luaH_realasize(t) / 2) {
        t->alimit = boundary;  /* use it as the new limit */
        setnorealasize(t);
      }
      return boundary;
    }
  }
  /* 'limit'==0或者表中存在t[limit] */
  if (!limitequalsasize(t)) {  /* (2)? */
    /* 'limit' > 0 and array has more elements after 'limit' */
    if (isempty(&t->array[limit]))  /* 'limit + 1' is empty? */
      return limit;  /* this is the boundary */
    /* else, try last element in the array */
    limit = luaH_realasize(t);
    if (isempty(&t->array[limit - 1])) {  /* empty? */
      /* there must be a boundary in the array after old limit, and it must be a valid new limit */
      unsigned int boundary = binsearch(t->array, t->alimit, limit);
      t->alimit = boundary;
      return boundary;
    }
    /* 否则，table中存在新的limit，检查hash表 */
  }
  /* (3)'limit' is the last element and either is zero or present in table */
  lua_assert(limit == luaH_realasize(t) &&
             (limit == 0 || !isempty(&t->array[limit - 1])));
  if (isdummy(t) || isempty(luaH_getint(t, cast(lua_Integer, limit + 1))))
    return limit;  /* 'limit + 1'是缺省key */
  else  /* 'limit + 1' is also present */
    return hash_search(t, limit);
}



#if defined(LUA_DEBUG)

/* export these functions for the test library */

Node *luaH_mainposition (const Table *t, const TValue *key) {
  return mainpositionTV(t, key);
}

#endif
